#include "EPollPoller.h"
#include "Logger.h"
#include "Channel.h"

#include <errno.h>
#include <unistd.h>
#include <cstring>

// index_就对应这里的含义
const int kNew = -1;     // Channel没添加到Epoll  // channel的成员index_ = -1
const int kAdded = 1;    // Channel添加到了Epoll
const int kDeleted = 2;  // Channel从Epoll中删除

static const int size = 5;

EPollPoller::EPollPoller(EventLoop* loop)
    :Poller(loop)
    ,epollfd_(::epoll_create(size))
    ,events_(kInitEventListSize) // vector<epoll_event>
{
    if(epollfd_ < 0)
    {
        LOG_FATAL("epoll_create errno:%d \n",errno);
    }
}

EPollPoller::~EPollPoller()
{
    close(epollfd_);
}

// 监听fd上的事件
// epoll_wait监听到的事件通过ChannelList* activeChannels输出给EventLoop
Timestamp EPollPoller::poll(int timeoutMs,ChannelList* activeChannels)
{
    // 实际上应该用LOG_DEBUG输出日志更为合理
    LOG_INFO("func=%s => fd total count:%lu \n",__FUNCTION__,channels_.size());

    // 正常来说第二个参数是struct epoll_event 对象的起始地址，但是我的events_是在vector中的
    // 扩容版的，地址会改变
    // 解引用：拿到第一个元素
    // 取地址：第一个元素的地址，也就是首地址
    int numEvents = epoll_wait(epollfd_,&*events_.begin(),static_cast<int>(events_.size()),timeoutMs);
    int saveErrno = errno; // 一个线程就是一个EventLoop，errno可能在其他线程中被修改，errno是全局的

    Timestamp now(Timestamp::now());

    if(numEvents > 0)
    {
        LOG_INFO("%d events happend \n",numEvents);
        fillActiveChannels(numEvents,activeChannels);
        if(numEvents == events_.size())
        {
            events_.resize(events_.size()*2);
        }
    }
    else if(numEvents == 0)
    {
        LOG_DEBUG("%s timeout! \n",__FUNCTION__);
    }
    else{
        errno = saveErrno; // mudou库因为LOG_ERRNO：要用到errno实现
        LOG_FATAL("EPollPoller::poll() err!");
    }
    return now;
}

// channel update remove => EeventLoop updateChannel removeChannel => Poller updateChannel removeChannel
/*
*           EventLoop  => poller.poll
*   ChannelList     Poller
*                 ChannelMap <fd,Channel*>     epollfd
*/
void EPollPoller::updateChannel(Channel* channel)
{
    const int index = channel->index();
    LOG_INFO("func=%s => fd=%d events=%d index=%d \n",__FUNCTION__,channel->fd(),channel->evevts(),index);

    if(index == kNew || index == kDeleted)
    {
        if(index == kNew)
        {
            int fd = channel->fd();
            channels_[fd] = channel;// 注册进来
        }

        channel->set_index(kAdded);
        update(EPOLL_CTL_ADD,channel);
    }
    else // channel已经在poller上注册过了
    {
        int fd = channel->fd();
        if(channel->isNoneEvent())
        {
            update(EPOLL_CTL_DEL,channel);
            channel->set_index(kDeleted);
        }
        else // 对读或写事件感兴趣
        {
            update(EPOLL_CTL_MOD,channel);
        }
    }
}

// 从poller中删除channel
void EPollPoller::removeChannel(Channel* channel)
{
    int fd = channel->fd();
    channels_.erase(fd);

    LOG_INFO("func=%s => fd=%d\n",__FUNCTION__,fd);

    int index = channel->index();
    if(index == kAdded)
    {
        update(EPOLL_CTL_DEL,channel);
    }
    channel->set_index(kNew);
}

    
// 填写活跃的连接
void EPollPoller::fillActiveChannels(int numEvents,ChannelList *activeChannels) const
{
    for(int i= 0;i < numEvents; ++i)
    {
        Channel* channel = static_cast<Channel*>(events_[i].data.ptr);// events_[i].data.ptr:返回值是void*
        channel->set_revents(events_[i].events);
        activeChannels->push_back(channel); // EventLoop就拿到了他的poller给他返回的所有发生事件的channel列表了
    }
}

// 更新Channel通道 epoll_ctl add/mod/del
void EPollPoller::update(int operation,Channel* channel)
{
    struct epoll_event event;
    memset(&event,0,sizeof(event));
    int fd = channel->fd();
    event.events = channel->evevts();
    event.data.fd = fd;
    event.data.ptr = channel;

    if(epoll_ctl(epollfd_,operation,fd,&event) < 0)// 只是删除错了，还能挽回
    {
        if(operation == EPOLL_CTL_DEL)
        {
            LOG_ERROR("epoll_ctl del error:%d\n",errno);
        }
        else
        {
            LOG_FATAL("epoll_ctl add/mod error:%d\n",errno);
        }
    }
}
